home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-01-15 | 6.9 KB | 274 lines | [TEXT/PJMM] |
- program LoopSndDemo;
-
- {Based on sndDemo by Marv Westrom, with major modifications by Ingemar Ragnemalm.}
-
- {This demo plays sampled music continuously, able to repeat one sample or switching}
- {between them. A callback procedure is used for immediately starting the next sample}
- {when the previous has finished.}
-
- {I sampled the music from Frank Zappa's "Ya Hozna". Please make your own samples for}
- {your games. This is just for the demo.}
-
- uses
- {$IFC UNDEFINED THINK_PASCAL}
- Types, QuickDraw, Events, Menus, Dialogs, Fonts, Resources, Devices,{}
- Memory, WIndows, TextEdit, OSUtils, MixedMode, Processes,
- {$ELSEC}
- {$SETC GENERATINGPOWERPC := false}
- {$ENDC}
- Sound;
-
-
- {Memory management calls for holding interrupt code in memory, for compatibility with}
- {Virtual Memory. I couldn't find these in Think Pascal, so I'm adding them here. They should}
- {be available in the Univ Interfaces.}
- {$IFC UNDEFINED THINK_PASCAL}
- {$ELSEC}
- function HoldMemory (address: univ Ptr; count: LONGINT): OSErr;
- inline
- $225F, $205F, $7000, $A05C, $3E80;
- function UnholdMemory (address: univ Ptr; count: LONGINT): OSErr;
- inline
- $225F, $205F, $7001, $A05C, $3E80;
- {$ENDC}
-
- var { necessary globals }
- gMySndChannel: SndChannelPtr;
-
- type
- IntPtr = ^INTEGER;
-
- {We assume format 1 here. That should be fixed so format 2 is also allowed}
- function SndData (sh: Handle): Ptr; { sh must be locked upon call }
- var
- s, c: INTEGER;
- p: Ptr;
- begin
- p := sh^;
- if IntPtr(p)^ = firstSoundFormat then
- begin
- s := IntPtr(ORD4(p) + 2)^;
- p := Ptr(ORD4(p) + s * 6);
- end;
- p := Ptr(ORD4(p) + 4);
- c := IntPtr(p)^;
- SndData := Ptr(ORD4(p) + 2 + c * 8);
- end; {SndData}
-
- {$PUSH}
- {$D-}
- {The A5 stuff is not necessary since I don't use any globals from callback}
- {I included it just in case it becomes interesting later.}
- procedure MyCallBack (chan: sndChannelPtr; var cmd: SndCommand);
- var
- myA5: longint;
- mySndCmd: SndCommand;
- myErr: OSErr;
- begin
- if cmd.param1 = 99 then
- begin
- myA5 := SetA5(chan^.userInfo);
-
- mySndCmd.cmd := bufferCmd;
- mySndCmd.param1 := 0;
- mySndCmd.param2 := cmd.param2;
- myErr := SndDoCommand(chan, mySndCmd, false);
-
- mySndCmd.cmd := callBackCmd;
- mySndCmd.param1 := 99; { arbitrary code to check MyCallback }
- mySndCmd.param2 := cmd.param2;
- myErr := SndDoCommand(chan, mySndCmd, false);
-
- myA5 := SetA5(myA5);
- end;
- end; {MyCallBack}
- {$POP}
-
- function AllocateSoundChannel: SndChannelPtr;
- var
- myErr: OSErr;
- theChannel: SndChannelPtr;
- {$IFC GENERATINGPOWERPC }
- callbackProc: ProcPtr;
- {$ENDC}
- begin
- theChannel := nil;
- {$IFC GENERATINGPOWERPC}
- callbackProc := NewRoutineDescriptor(@MyCallBack, uppSndCallBackProcInfo, GetCurrentArchitecture); {GetCurrentISA?}
- myErr := SndNewChannel(theChannel, 5, initMono + initNoInterp, callbackProc);
- {$ELSEC}
- myErr := SndNewChannel(theChannel, 5, initMono + initNoInterp, @MyCallBack);
- {$ENDC}
- theChannel^.userInfo := SetCurrentA5; {Not necessary since I don't use any globals from callback - but you may want to}
- AllocateSoundChannel := theChannel;
- end; {AllocateSoundChannel}
-
- procedure AsynchChangePlay (sndH, loopH: handle);
- var
- mySndCmd: sndCommand;
- myErr: OSErr;
- begin
- if gMySndChannel = nil then
- gMySndChannel := AllocateSoundChannel;
- if gMySndChannel = nil then
- Exit(AsynchChangePlay);
-
- if (sndH = nil) or (loopH = nil) then
- Exit(AsynchChangePlay);
-
- mySndCmd.cmd := flushCmd;
- mySndCmd.param1 := 0;
- mySndCmd.param2 := 0;
- myErr := SndDoImmediate(gMySndChannel, mySndCmd);
-
- mySndCmd.cmd := bufferCmd;
- mySndCmd.param1 := 0;
- mySndCmd.param2 := Ord4(SndData(sndH));
- myErr := SndDoCommand(gMySndChannel, mySndCmd, false);
-
- mySndCmd.cmd := callBackCmd;
- mySndCmd.param1 := 99;
- mySndCmd.param2 := Ord4(SndData(loopH));
- myErr := SndDoCommand(gMySndChannel, mySndCmd, false);
-
- end; {AsynchChangePlay}
-
- procedure AsyncEndPlay;
- var
- mySndCmd: sndCommand;
- myErr: OSErr;
- begin
- mySndCmd.cmd := quietCmd;
- myErr := SndDoCommand(gMySndChannel, mySndCmd, false);
- myErr := SndDisposeChannel(gMySndChannel, true);
- end; {AsyncEndPlay}
-
- procedure InitMacintosh;
- begin
- {$IFC UNDEFINED THINK_PASCAL}
- MaxApplZone;
-
- InitGraf(@qd.thePort);
- InitFonts;
- FlushEvents(everyEvent, 0);
- InitWindows;
- InitMenus;
- TEInit;
- InitDialogs(nil);
- {$ENDC}
- InitCursor;
- end; {InitMacintosh}
-
-
- function GetNamedSound (name: Str255): Handle;
- var
- sndH: Handle;
- begin
- sndH := GetNamedResource('snd ', name);
- if sndH <> nil then
- begin
- LoadResource(sndH);
- MoveHHi(sndH);
- Hlock(sndH);
- GetNamedSound := sndH;
- end;
- end; {GetNamedSound}
-
- {Variables that are local to the main procedure.}
- var
- sndHiThere: Handle;
- sndPrelude, sndStart, sndMain, sndAlt: Handle;
- i, times: integer;
- startTicks: Longint;
- const
- kDelayTime = 1;
- kHoldHowMuch = 1000;
- var
- err: OSErr;
-
- begin
- InitMacintosh;
-
- sndPrelude := GetNamedSound('Förspel');
- sndStart := GetNamedSound('Start');
- sndMain := GetNamedSound('Main test');
- sndAlt := GetNamedSound('Mellantest');
-
- {$IFC UNDEFINED THINK_PASCAL}
- {$ELSEC}
- ShowText;
- {$ENDC}
-
- WriteLn('Welcome to LoopSndDemo!');
- WriteLn('You should now hear a tune by Frank Zappa.');
- WriteLn('Click to advance phase.');
-
- {The callback function must never be swapped out by Virtual Memory!}
- {Unfortunately, there is no way that I know to get theexact size of a procedure.}
- {For example, the following is not reliable:}
- {if noErr <> HoldMemory(@MyCallBack, Longint(@AllocateSoundChannel) - Longint(@MyCallBack)) then}
- {In my experiments, it seems correct when using 68k code, but not with PPC code, since the order}
- {of procedures are different. Instead, I use a constant kHoldHowMuch. If it is large enough, it should work.}
-
- err := HoldMemory(@MyCallBack, kHoldHowMuch);
- if noErr <> err then
- WriteLn('Error when calling HoldMemory!', err);
-
- {Allocate the sound channel by calling AllocateSoundChannel.}
- gMySndChannel := AllocateSoundChannel;
-
- AsynchChangePlay(sndPrelude, sndPrelude);
- i := 0;
- repeat
- i := i + 1;
- Write(i : 3, ' ');
- if (i mod 25) = 0 then
- WriteLn;
- Delay(kDelayTime, startTicks);
- until Button;
- WriteLn(Char(13), 'Switch to phase 2!');
- while Button do
- ;
-
- AsynchChangePlay(sndStart, sndMain);
- repeat
- i := i + 1;
- Write(i : 3, ' ');
- if (i mod 25) = 0 then
- WriteLn;
- Delay(kDelayTime, startTicks);
- until Button;
- WriteLn(Char(13), 'Switch to phase 3!');
- while Button do
- ;
-
- AsynchChangePlay(sndAlt, sndAlt);
- repeat
- i := i + 1;
- Write(i : 3, ' ');
- if (i mod 25) = 0 then
- WriteLn;
- Delay(kDelayTime, startTicks);
- until Button;
- WriteLn(Char(13), 'Switch to phase 4!');
- while Button do
- ;
-
- AsynchChangePlay(sndMain, sndMain);
- repeat
- i := i + 1;
- Write(i : 3, ' ');
- if (i mod 25) = 0 then
- WriteLn;
- Delay(kDelayTime, startTicks);
- until Button;
- WriteLn(Char(13), 'Quitting!');
-
- AsyncEndplay;
-
- {Release the callback from being unswappable.}
- if noErr <> UnholdMemory(@MyCallBack, kHoldHowMuch) then
- WriteLn('Error when calling UnholdMemory!');
-
- ExitToShell; {To avoid stupid SIOUX "save?" questions.}
- end.